package web

import (
	"fmt"
	"io"
	"log"
	"net/http"
	"os"
	"strings"
	"time"

	"gitee.com/dingiyan/goMyAdmin/db"
	"github.com/gin-contrib/sessions"

	// "github.com/gin-contrib/sessions/cookie"

	"github.com/gin-contrib/sessions/gorm"
	"github.com/gin-gonic/gin"
)

// 初始化gin app
func InitGinApp() *gin.Engine {
	if os.Getenv("APP_RUN_MODE") == "prod" {
		gin.SetMode(gin.ReleaseMode)
	}
	// 日志输出到文件
	if info, _ := os.Stat("./log"); info == nil {
		os.Mkdir("./log", 0755)
	}
	theMins := time.Now().Format("200601021504")
	f, _ := os.Create(fmt.Sprintf("./log/goMyAdmin-%v.log", theMins))
	gin.DefaultWriter = io.MultiWriter(f, os.Stdout)
	log.SetOutput(gin.DefaultWriter)

	ginApp := gin.Default()
	initSession(ginApp)

	// middleware
	ginApp.Use(cors())
	ginApp.Use(gin.Logger())
	ginApp.Use(gin.Recovery())
	ginApp.Use(bizAuth())
	ginApp.Use(static404())
	// ginApp.Use(staticFrontendFiles())

	InitRouter(ginApp)
	return ginApp
}

// 初始化session
func initSession(ginApp *gin.Engine) {
	sessionStore := gorm.NewStore(db.DB, true, []byte("sessionSecertklsd09234u8jnfidrgh23olik4589lsd"))
	// use session
	// sessionStore := cookie.NewStore([]byte("sessionSecertklsd09234u8jnfidrgh23olik4589lsd"))
	// 	sessionStore.Options(&sessions.Options{

	// 	}
	// )
	ginApp.Use(sessions.Sessions("ginsession", sessionStore))

}

// 业务，验证授权中间件，使用session 验证
func bizAuth() gin.HandlerFunc {
	return func(c *gin.Context) {
		path := c.Request.URL.Path
		// 不处理非api
		if !strings.HasPrefix(path, "/api") {
			return
		}
		if path == "/api/login" {
			return
		}
		// fmt.Println(path)
		session := sessions.Default(c)
		userId := session.Get("userId")
		fmt.Printf("登录session userId: %v\n", userId)
		fmt.Printf("登录session userEmail: %v\n", session.Get("email"))
		if userId == nil {
			// c.Redirect(302, "/goMyAdmin/login")
			c.JSON(http.StatusUnauthorized, gin.H{"code": 401, "msg": "unauthorized"})
			c.Abort()
			return
		}

		c.Set("userId", userId)
		c.Set("email", session.Get("email"))
		c.Set("userName", session.Get("userName"))

	}
}

// 如果不是api，则当结果是404时，自动输出index.html，实现前端history模式特殊处理。
func static404() gin.HandlerFunc {
	return func(c *gin.Context) {
		if strings.HasPrefix(c.Request.URL.Path, "/api") {
			return
		}
		c.Next()
		if c.Writer.Status() == 404 {
			c.Status(http.StatusOK)
			c.Writer.Write(staticIndexHTML)
			c.Header("Content-Type", "text/html")
			c.Abort()
		}
	}
}

// 处理跨域中间件，开发时需要
func cors() gin.HandlerFunc {
	return func(c *gin.Context) {
		// 设置允许跨域请求的源
		c.Writer.Header().Set("Access-Control-Allow-Origin", "*")

		// 也可以设置为特定的源，例如 "http://example.com"
		// c.Writer.Header().Set("Access-Control-Allow-Origin", "http://example.com")

		// 允许请求的方法
		c.Writer.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE, UPDATE")

		// 允许请求的头部
		c.Writer.Header().Set("Access-Control-Allow-Headers", "Origin, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization")

		// 设置预检请求的缓存时间
		c.Writer.Header().Set("Access-Control-Max-Age", "86400")

		// 允许携带凭证（cookies）
		c.Writer.Header().Set("Access-Control-Allow-Credentials", "true")

		// 如果是预检请求（OPTIONS），则直接返回
		if c.Request.Method == "OPTIONS" {
			c.AbortWithStatus(204)
			return
		}

		// 继续后续处理
		c.Next()
	}
}

// study 前端静态资源提供，仅学习，如果要使用embed，需要
// func staticFrontendFiles() gin.HandlerFunc {
// 	ss, _ := fs.Sub(staticFrontend, "dist")

// 	httpFS := http.FS(ss)
// 	return func(c *gin.Context) {
// 		path := c.Request.URL.Path
// 		if strings.HasPrefix(path, "/api") {
// 			return
// 		}
// 		fmt.Println("static", path)
// 		if path == "/" {
// 			_, err := staticFrontend.ReadFile("dist/index.html")
// 			if err != nil {
// 				fmt.Println(err)
// 				c.Status(http.StatusNotFound)
// 				c.Abort()
// 				return
// 			}
// 			c.FileFromFS("index.html", httpFS)

// 			c.Status(http.StatusOK)
// 			c.Abort()
// 			return
// 		}

// 		filePath := "dist" + path
// 		_, err := staticFrontend.ReadFile(filePath)
// 		if err != nil {
// 			//  未找到文件，退回使用index.html ,因为前端history模式
// 			c.FileFromFS("index.html", httpFS)
// 			c.Status(http.StatusOK)
// 			c.Abort()
// 		} else {
// 			c.Status(http.StatusOK)
// 			c.FileFromFS(path, httpFS)
// 			c.Abort()
// 		}

// 	}
// }
